package com.sitech.ismp.workflow.engine;

import com.sitech.ismp.common.exception.BsmException;
import com.sitech.ismp.common.service.SerialService;
import com.sitech.ismp.workflow.basic.TblActivity;
import com.sitech.ismp.workflow.dao.TaskDAO;
import com.sitech.ismp.workflow.domain.*;
import com.sitech.ismp.workflow.rule.DBRuleTask;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;

public class Activity {
    private Log logger = LogFactory.getLog(getClass());
    protected TaskManager taskMgr;
    private RoutingRuleManager routingRuleManager;
    private SerialService serialService;
    private ActivityQueryService activityQueryService;
    private ParticipantService participantService;
    private RoutingService routingService;
    private RoutingRuleQueryService routingRuleQueryService;
    private TaskQueryService taskQueryService;
    private ProcessManager processManager;
    private DBRuleTask dbRuleTask;
    private TimeoutCalculate timeoutCalculate;
    private TaskDAO taskDAO;
    private AgentService agentService;
    private WorkflowNotifyFactory workflowNotifyFactory;
    private ActivityExtend activityExtend;
    private SubflowService subflowService;

    public Activity() {
    }

    public Task initialize(int processId, String title, String staffId) {
        this.logger.debug("initialize： processId = " + processId);
        Task startTask = addInitalTask(processId, title, staffId);
        this.logger.debug("added start Node： taskId = " + startTask.getTaskId() + ", iSerialNo:" + startTask.getSerialNo());
        return startTask;
    }

    public List<Task> submit(Task task, String title, String taskDeadline) {
        this.logger.debug("RUN: submit(" + task.getTaskId() + ")");


        List<Task> taskList = addToDoTaskList(task, 0, 0, title, taskDeadline);

        return taskList;
    }

    public Task save(int taskId, String title, String user) {
        return this.activityExtend.save(taskId, title, user);
    }

    public boolean browseTask(int taskId, String user, String desc) {
        return this.activityExtend.browseTask(taskId, user, desc);
    }

    public String deleteProcessInstance(int serialNo, String deleteChildren, String user, String desc) {
        return this.activityExtend.deleteProcessInstance(serialNo, deleteChildren,
                user, desc);
    }

    public Task initWithInteraction(int processId, int serialNo, int taskId, String user, String title, String deadline) {
        Task startTask = addInitalTaskWithSerialNo(processId, title, user, serialNo);

        this.taskMgr.haveDoneTask(startTask, 0);

        List<RoutingRule> routingRuleList = this.routingService.getRoutingRule(startTask);
        if (routingRuleList.size() == 1) {
            RoutingRule routingRule = (RoutingRule) routingRuleList.get(0);
            int nextActivityId = Integer.valueOf(routingRule.getNextActIdList()).intValue();
            ActivityInfo nextActivityInfo = this.activityQueryService.getActivity(nextActivityId);
            int nextActivityType = nextActivityInfo.getActivityType();

            Task newTask = this.activityExtend.buildTask(nextActivityType, null, nextActivityId, user, null, null, new Date(), null,
                    startTask.getTaskId(), null, 0, null, 0, 0, startTask.getCurrActId(), startTask.getTaskId(),
                    processId, serialNo, user, "", taskId, 0, startTask.getTitle());


            List<Date> timeLimitList = this.timeoutCalculate.getTaskTimeLimit(newTask, "");
            newTask.setDateAllow((Date) timeLimitList.get(0));
            newTask.setBizDeadline((Date) timeLimitList.get(1));

            newTask = this.taskMgr.addToDoTask(newTask);
            if (startTask.getActivityType() == 1) {
                this.logger.debug("Attention:db rule exec here.");

                String table_name = "HAVEDONETASKS";

                table_name = table_name + nextActivityInfo.getProcessId();


                this.dbRuleTask.start(table_name, startTask.getTaskId(), "2");
            }
            return newTask;
        }
        BsmException bsmException = new BsmException("", "异步提交只支持开始节点后只有一个节点， 并且节点类型为交互节点");
        this.logger.error("initWithInteraction error! After startNode , there are two or more interaction.",
                bsmException);
        throw bsmException;
    }

    public Task transferTask(int taskId, Participant participant, String user) {
        return this.activityExtend.transferTask(taskId, participant, user);
    }

    public Task noticeTask(int taskId, String message, String noticeType, String user) {
        return this.activityExtend.noticeTask(taskId, message, noticeType, user);
    }

    public Task claimTask(int taskId, String user) {
        return this.activityExtend.claimTask(taskId, user);
    }

    public Task releaseTask(int taskId, String user) {
        return this.activityExtend.releaseTask(taskId, user);
    }

    public void terminateProcess(int serialNo, String user, String desc) {
        this.activityExtend.terminateProcess(serialNo, user, desc);
    }

    public void renewProcess(int serialNo, String user, String desc) {
        this.activityExtend.renewProcess(serialNo, user, desc);
    }

    public Task suspendTask(int taskId, String user, String desc) {
        return this.activityExtend.suspendTask(taskId, user, desc);
    }

    public Task wakeupTask(int taskId, String user, String desc) {
        return this.activityExtend.wakeupTask(taskId, user, desc);
    }

    public Task returnBackTask(Task curTask, String user, String desc) {
        return this.activityExtend.returnBackTask(curTask, user, desc);
    }

    public boolean callBackTask(int processId, int serialNo, int taskId, String user, String desc) {
        this.logger.info("日期:" + new Date() + ",用户：" + user + "作任务（任务ID：" + taskId + "）追回操作。");
        return this.taskMgr.callBackTask(processId, serialNo, taskId, user, desc);
    }

    public void suspendProcess(ProcessInstance processInstance, String user, String desc) {
        this.logger.info("日期:" + new Date() + ",用户：" + user + "作工单（工单实例号：" + processInstance.getSerialNo() + "）挂起操作。");
        this.processManager.suspendProcess(processInstance);
    }

    public void wakeupProcess(ProcessInstance processInstance, String user, String desc) {
        this.logger.info("日期:" + new Date() + ",用户：" + user + "作工单（工单实例号：" + processInstance.getSerialNo() + "）唤醒操作。");
        this.processManager.wakeupProcessInstance(processInstance);
    }

    private List<Task> addToDoTaskList(Task task, int iPreActiveTaskId, int iPreActiveActId, String title, String taskDeadline) {
        int taskId = task.getTaskId();
        if ((title != null) && (!title.equals(""))) {
            task.setTitle(title);
        }
        if (task != null) {
            if (task.getActivityType() != 12) {
                this.taskMgr.haveDoneTask(task, 0);

                this.timeoutCalculate.setTaskEnd(task);
                this.workflowNotifyFactory.notifyTaskComplete(task);

                this.timeoutCalculate.setManyTaskEnd(task);
            }
        } else {
            this.logger.error("Can find task from to_do_task_list. TaskId = " + taskId);
            throw new BsmException("", "没有从表中获取到待提交任务");
        }
        int isAllow = this.routingRuleManager.checkComplte(task);
        if (isAllow == 0) {
            if (task.getActivityType() == 12) {
                List<Task> andMergeTaskList = this.taskQueryService.queryTaskByActivityId(task.getSerialNo(),
                        task.getCurrActId(), task.getGrantorId());
                for (Task andMergetTask : andMergeTaskList) {
                    andMergetTask.setInstanceId(task.getInstanceId());
                    this.taskMgr.haveDoneTask(andMergetTask, 0);
                }
            }
            List<RoutingRule> routingRuleList = this.routingService.getRoutingRule(task);
            if ((routingRuleList != null) && (routingRuleList.size() > 0)) {
                return pushNext(task, routingRuleList, iPreActiveTaskId, iPreActiveActId, taskDeadline);
            }
        }
        return Collections.emptyList();
    }

    private List<Task> pushNext(Task task, List<RoutingRule> routingRuleList, int iPreActiveTaskIdIn, int iPreActiveActIdIn, String taskDeadline) {
        List<Task> newTaskList = new ArrayList();
        int iPreActiveTaskId = 0;
        int iPreActiveActId = 0;
        if (task.getActivityType() == 2) {
            iPreActiveTaskId = task.getTaskId();
            iPreActiveActId = task.getCurrActId();
        } else {
            iPreActiveTaskId = iPreActiveTaskIdIn;
            iPreActiveActId = iPreActiveActIdIn;
        }
        for (RoutingRule routingRule : routingRuleList) {
            List<Task> newTask = addNewTask(task, routingRule, iPreActiveTaskId, iPreActiveActId, taskDeadline);
            newTaskList.addAll(newTask);
        }
        return newTaskList;
    }

    private List<Task> addNewTask(Task task, RoutingRule routingRule, int iPreActiveTaskId, int iPreActiveActId, String taskDeadline) {
        int newTaskId = 0;

        int iNextActivityId = Integer.valueOf(routingRule.getNextActIdList()).intValue();
        ActivityInfo nextActivityInfo = this.activityQueryService.getActivity(iNextActivityId);

        int nextActivityType = nextActivityInfo.getActivityType();
        String grantorId = task.getGrantorId();
        if (task.getActivityType() == 11) {
            if ((grantorId != null) && (!"".equals(grantorId))) {
                grantorId = grantorId + "," + String.valueOf(task.getTaskId());
            } else {
                grantorId = String.valueOf(task.getTaskId());
            }
        } else if (task.getActivityType() == 12) {
            if (grantorId != null) {
                if (grantorId.lastIndexOf(",") > 0) {
                    grantorId = grantorId.substring(0, grantorId.lastIndexOf(","));
                } else {
                    grantorId = "";
                }
            }
        }
        Task newTask = new Task();
        newTask.setActivityType(nextActivityType);
        newTask.setCurrActId(iNextActivityId);
        newTask.setPreActId(task.getCurrActId());
        newTask.setSerialNo(task.getSerialNo());
        newTask.setGrantorId(grantorId);
        newTask.setPreTaskId(iPreActiveTaskId);
        newTask.setEntityId(task.getTaskId());
        newTask.setTitle(task.getTitle());
        newTask.setProcessId(task.getProcessId());
        newTask.setCurrDealer(task.getCurrDealer());
        newTask.setDateCreated(new Date());
        newTask.setFromInstanceId(task.getInstanceId());
        if ((nextActivityType == 2) || (nextActivityType == 16)) {
            String isBeginAct = nextActivityInfo.getIsBeginAct();
            boolean beginFlag = (isBeginAct != null) && ("1".equals(isBeginAct));
            List<Participant> participantList = new ArrayList();
            if (beginFlag) {
                Participant participant = new Participant();
                participant.setParticipantType(4);
                participant.setParticipantValue(task.getCurrDealer());
                participantList.add(participant);
            } else {
                participantList = this.participantService.getParticipant(task.getProcessId(), task.getSerialNo(),
                        iNextActivityId, iPreActiveActId, task.getCurrActId(), task.getInstanceId());
            }
            if ((participantList != null) && (participantList.size() > 0)) {
                for (Participant participant : participantList) {
                    newTask.setTaskId(-1);
                    newTaskId = this.taskDAO.getNewTaskId();
                    if (String.valueOf(0).equals(
                            nextActivityInfo.getWorkItemType())) {
                        if (newTask.getInstanceId() <= 0) {
                            newTask.setInstanceId(newTaskId);
                        }
                    } else {
                        newTask.setInstanceId(newTaskId);
                    }
                    if (4 == participant.getParticipantType()) {
                        newTask.setTaskId(newTaskId);

                        String staffId = participant.getParticipantValue();

                        Agent agent = this.agentService.queryAgent(staffId);
                        if (!beginFlag) {
                            if ((agent != null) && (agent.getAgentMen() != null) && (!"".equals(agent.getAgentMen()))) {
                                staffId = agent.getAgentMen();
                                this.agentService.addAgentDetail(agent.getAgentCode(),
                                        String.valueOf(newTask.getSerialNo()), String.valueOf(newTaskId),
                                        newTask.getCurrActId(), nextActivityInfo.getActivityName());
                            }
                        }
                        newTask.setStaffId(staffId);
                        newTask.setStaffWg("");

                        List<Date> timeLimitList = this.timeoutCalculate.getTaskTimeLimit(newTask, taskDeadline);
                        newTask.setDateAllow((Date) timeLimitList.get(0));
                        newTask.setBizDeadline((Date) timeLimitList.get(1));
                        if ("-1".equals(newTask.getStaffId())) {
                            newTask.setTaskStatus(2);
                        } else {
                            newTask.setTaskStatus(1);
                        }
                        if ((isBeginAct != null) && (!isBeginAct.equals("1")) && (!isBeginAct.equals("0"))) {
                            if ((agent != null) && (agent.getClientMen() != null) && (!"".equals(agent.getClientMen())) && (
                                    (agent.getMsgSendTo() == 2) ||
                                            (agent.getMsgSendTo() == 3))) {
                                String orignalPerson = newTask.getStaffId();
                                newTask.setStaffId(agent.getClientMen());
                                this.activityExtend.insertSheetReachToTbIsmMsgSet(newTask);
                                newTask.setStaffId(orignalPerson);
                            }
                            this.activityExtend.insertSheetReachToTbIsmMsgSet(newTask);
                        }
                        newTaskId = this.taskMgr.addToDoTask(newTask).getTaskId();
                        this.workflowNotifyFactory.notifyTaskCreate(newTask);
                    } else if (1 == participant.getParticipantType()) {
                        String staffWg = participant.getParticipantValue();

                        newTask.setStaffId("");
                        newTask.setStaffWg(staffWg);

                        newTask.setTaskId(newTaskId);

                        List<Date> timeLimitList = this.timeoutCalculate.getTaskTimeLimit(newTask, taskDeadline);
                        newTask.setDateAllow((Date) timeLimitList.get(0));
                        newTask.setBizDeadline((Date) timeLimitList.get(1));
                        newTask.setTaskStatus(2);
                        if ((isBeginAct != null) && (!isBeginAct.equals("1")) && (!isBeginAct.equals("0"))) {
                            this.activityExtend.insertSheetReachToTbIsmMsgSet(newTask);
                        }
                        newTaskId = this.taskMgr.addToDoTask(newTask).getTaskId();
                        this.workflowNotifyFactory.notifyTaskCreate(newTask);
                    }
                    if (nextActivityType == 16) {
                        String staffId = participant.getParticipantValue();

                        this.subflowService.initSubFlow(newTask, nextActivityInfo, staffId);
                    }
                }
            }
        } else {
            newTaskId = this.taskMgr.addToDoTask(newTask).getTaskId();
            this.workflowNotifyFactory.notifyTaskCreate(newTask);
        }
        this.logger.debug("iNextActivityId:" + iNextActivityId + ",iActivityType:" + task.getActivityType());

        this.activityExtend.postAction(task, nextActivityInfo, iPreActiveTaskId);
        if ((nextActivityInfo.getActivityType() != 2) &&
                (nextActivityInfo.getActivityType() != 10) && ((nextActivityInfo.getActivityType() != 16) || (!"0".equals(nextActivityInfo.getSubflowType())))) {
            this.logger.debug("re call:" + newTaskId + "," + nextActivityInfo.getActivityId());
            return addToDoTaskList(newTask, iPreActiveTaskId, iPreActiveActId, task.getTitle(), taskDeadline);
        } else {
            this.activityExtend.preAction(nextActivityInfo, newTaskId);
            if (nextActivityInfo.getActivityType() == 10) {
                this.activityExtend.completeProcess(task.getSerialNo(), newTaskId);
            }
        }
        return Arrays.asList(newTask);
    }

    private Task addInitalTask(int iProcessId, String title, String staffId) {
        this.logger.debug("addInitalTask start:iProcessId = " + iProcessId + ",title = " + title + ",staffId = " + staffId);

        int iSerialNo = Integer.valueOf(this.serialService.newSerialNo("processInstance")).intValue();


        ActivityInfo activityInfo = this.activityQueryService.getStartActivity(iProcessId);
        TblActivity tblActivity = this.activityQueryService.change(activityInfo);

        Task task = this.taskMgr.addToDoTask(tblActivity, 0, iSerialNo, "0", 0, staffId, null, title, 0, "");
        this.activityExtend.preAction(activityInfo, task.getTaskId());
        this.logger.debug("addInitalTask end :serialNo = " + iSerialNo + ",TaskId = " + task.getTaskId());
        return task;
    }

    private Task addInitalTaskWithSerialNo(int iProcessId, String titleIn, String istaffIdIn, int serialNo) {
        this.logger.debug("addInitalTask start:iProcessId = " + iProcessId + ",title = " + titleIn + ",staffId = " +
                istaffIdIn);


        ActivityInfo activityInfo = this.activityQueryService.getStartActivity(iProcessId);
        TblActivity tblActivity = this.activityQueryService.change(activityInfo);

        Task task = this.taskMgr.addToDoTask(tblActivity, 0, serialNo, "0", 0, istaffIdIn, null, titleIn, 0, "");
        this.activityExtend.preAction(activityInfo, task.getTaskId());
        this.logger.debug("addInitalTask end :serialNo = " + serialNo + ",TaskId = " + task.getTaskId());
        return task;
    }

    public void reOpenSheet(String processId, String serialNo, String activityId, String user, String desc) {
        this.activityExtend.reOpenSheet(processId, serialNo, activityId, user, desc);
    }

    public TaskManager getTaskManager() {
        return this.taskMgr;
    }

    public void setTaskManager(TaskManager taskManager) {
        this.taskMgr = taskManager;
    }

    public RoutingRuleManager getRoutingRuleManager() {
        return this.routingRuleManager;
    }

    public void setRoutingRuleManager(RoutingRuleManager routingRuleManager) {
        this.routingRuleManager = routingRuleManager;
    }

    public SerialService getSerialService() {
        return this.serialService;
    }

    public void setSerialService(SerialService serialService) {
        this.serialService = serialService;
    }

    public ActivityQueryService getActivityQueryService() {
        return this.activityQueryService;
    }

    public void setActivityQueryService(ActivityQueryService activityQueryService) {
        this.activityQueryService = activityQueryService;
    }

    public ParticipantService getParticipantService() {
        return this.participantService;
    }

    public void setParticipantService(ParticipantService participantService) {
        this.participantService = participantService;
    }

    public RoutingService getRoutingService() {
        return this.routingService;
    }

    public void setRoutingService(RoutingService routingService) {
        this.routingService = routingService;
    }

    public TaskQueryService getTaskQueryService() {
        return this.taskQueryService;
    }

    public void setTaskQueryService(TaskQueryService taskQueryService) {
        this.taskQueryService = taskQueryService;
    }

    public ProcessManager getProcessManager() {
        return this.processManager;
    }

    public void setProcessManager(ProcessManager processManager) {
        this.processManager = processManager;
    }

    public TimeoutCalculate getTimeoutCalculate() {
        return this.timeoutCalculate;
    }

    public void setTimeoutCalculate(TimeoutCalculate timeoutCalculate) {
        this.timeoutCalculate = timeoutCalculate;
    }

    public DBRuleTask getDbRuleTask() {
        return this.dbRuleTask;
    }

    public void setDbRuleTask(DBRuleTask dbRuleTask) {
        this.dbRuleTask = dbRuleTask;
    }

    public TaskDAO getTaskDAO() {
        return this.taskDAO;
    }

    public void setTaskDAO(TaskDAO taskDAO) {
        this.taskDAO = taskDAO;
    }

    public RoutingRuleQueryService getRoutingRuleQueryService() {
        return this.routingRuleQueryService;
    }

    public void setRoutingRuleQueryService(RoutingRuleQueryService routingRuleQueryService) {
        this.routingRuleQueryService = routingRuleQueryService;
    }

    public TaskManager getTaskMgr() {
        return this.taskMgr;
    }

    public void setTaskMgr(TaskManager taskMgr) {
        this.taskMgr = taskMgr;
    }

    public AgentService getAgentService() {
        return this.agentService;
    }

    public void setAgentService(AgentService agentService) {
        this.agentService = agentService;
    }

    public WorkflowNotifyFactory getWorkflowNotifyFactory() {
        return this.workflowNotifyFactory;
    }

    public void setWorkflowNotifyFactory(WorkflowNotifyFactory workflowNotifyFactory) {
        this.workflowNotifyFactory = workflowNotifyFactory;
    }

    public ActivityExtend getActivityExtend() {
        return this.activityExtend;
    }

    public void setActivityExtend(ActivityExtend activityExtend) {
        this.activityExtend = activityExtend;
    }

    public SubflowService getSubflowService() {
        return this.subflowService;
    }

    public void setSubflowService(SubflowService subflowService) {
        this.subflowService = subflowService;
    }
}
